package com.gitee.wsl.compose.ui.richtext.edit.state

import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextRange
import com.gitee.wsl.compose.ui.richtext.edit.annotation.ExperimentalRichTextApi
import com.gitee.wsl.compose.ext.text.customMerge
import com.gitee.wsl.compose.ui.richtext.edit.model.span.ext.getCommonRichStyle
import com.gitee.wsl.compose.ui.richtext.edit.model.span.style.RichSpanStyle
import com.gitee.wsl.compose.ext.text.unmerge
import com.gitee.wsl.compose.ui.richtext.edit.model.span.ext.getCommonStyle
import kotlin.reflect.KClass


//RichSpanStyle

@OptIn(ExperimentalRichTextApi::class)
inline fun <reified T: RichSpanStyle> RichTextState.isRichSpan(): Boolean =
    isRichSpan(T::class)

@OptIn(ExperimentalRichTextApi::class)
fun RichTextState.isRichSpan(kClass: KClass<out RichSpanStyle>): Boolean {
    return (currentRichSpanStyle::class == kClass ||
            toAddRichSpanStyle::class == kClass) &&
            toRemoveRichSpanStyle != kClass
}

@OptIn(ExperimentalRichTextApi::class)
fun RichTextState.toggleRichSpan(spanStyle: RichSpanStyle) {
    if (isRichSpan(spanStyle::class))
        removeRichSpan(spanStyle)
    else
        addRichSpan(spanStyle)
}

@OptIn(ExperimentalRichTextApi::class)
fun RichTextState.addRichSpan(spanStyle: RichSpanStyle) {
    if (toRemoveRichSpanStyle::class == spanStyle)
        toRemoveRichSpanStyle = RichSpanStyle.Default::class
    toAddRichSpanStyle = spanStyle

    if (!selection.collapsed)
        applyRichSpanStyleToSelectedText()
}

@OptIn(ExperimentalRichTextApi::class)
fun RichTextState.removeRichSpan(spanStyle: RichSpanStyle) {
    if (toAddRichSpanStyle::class == spanStyle::class)
        toAddRichSpanStyle = RichSpanStyle.Default
    toRemoveRichSpanStyle = spanStyle::class

    if (!selection.collapsed)
        applyRichSpanStyleToSelectedText()
}

/**
 * Updates the [currentAppliedSpanStyle] to the [SpanStyle] that should be applied to the current selection.
 */
@OptIn(ExperimentalRichTextApi::class)
internal fun RichTextState.updateCurrentSpanStyle() {
    if (selection.collapsed) {
        val richSpan = getRichSpanByTextIndex(textIndex = selection.min - 1)

        currentAppliedRichSpanStyle = richSpan
            ?.fullStyle
            ?: RichSpanStyle.Default
        currentAppliedSpanStyle = richSpan
            ?.fullSpanStyle
            ?: RichSpanStyle.DefaultSpanStyle

//            if (
//                config.preserveStyleOnEmptyLine &&
//                (richSpan == null || (richSpan.isFirstInParagraph && richSpan.paragraph.isEmpty()))
//            ) {
//                val paragraphBefore =
//                    if (selection.min - 2 < 0)
//                        null
//                    else
//                        getRichParagraphByTextIndex(selection.min - 2)
//
//                if (paragraphBefore == null || paragraphBefore.isNotEmpty()) {
//                    toAddRichSpanStyle = currentRichSpanStyle
//                    toAddSpanStyle = currentSpanStyle
//                }
//            }
    } else {
        val richSpanList = getRichSpanListByTextRange(selection)

        currentAppliedRichSpanStyle = richSpanList
            .getCommonRichStyle()
            ?: RichSpanStyle.Default
        currentAppliedSpanStyle = richSpanList
            .getCommonStyle()
            ?: RichSpanStyle.DefaultSpanStyle
    }
}


/**
 * Handles adding or removing the style in [toAddSpanStyle] and [toRemoveSpanStyle] from a given [TextRange].
 *
 * @param textRange The [TextRange] to apply the styles to.
 */
@OptIn(ExperimentalRichTextApi::class)
internal fun RichTextState.applyRichSpanStyleToTextRange(
    textRange: TextRange
) {
    // Get the rich span list of the selected text
    val selectedRichSpanList = getRichSpanListByTextRange(textRange)

    val startSelectionIndex = textRange.min
    val endSelectionIndex = textRange.max

    // Loop through the rich span list
    for (i in selectedRichSpanList.lastIndex downTo 0) {
        val richSpan = selectedRichSpanList[i]

        // Get the text before, during, and after the selected text
        val beforeText =
            if (startSelectionIndex in richSpan.textRange)
                richSpan.text.substring(0, startSelectionIndex - richSpan.textRange.start)
            else
                ""

        val middleText =
            richSpan.text.substring(
                maxOf(startSelectionIndex - richSpan.textRange.start, 0),
                minOf(endSelectionIndex - richSpan.textRange.start, richSpan.text.length)
            )

        val afterText =
            if (endSelectionIndex - 1 in richSpan.textRange)
                richSpan.text.substring(endSelectionIndex - richSpan.textRange.start)
            else
                ""

        val richSpanFullSpanStyle = richSpan.fullSpanStyle
        val newSpanStyle = richSpanFullSpanStyle.customMerge(toAddSpanStyle).unmerge(toRemoveSpanStyle)

        val startApplyStyleIndex = maxOf(startSelectionIndex, richSpan.textRange.start)

        handleUpdatingRichSpan(
            richSpan = richSpan,
            startIndex = startApplyStyleIndex,
            beforeText = beforeText,
            middleText = middleText,
            afterText = afterText,
            newSpanStyle = newSpanStyle,
        )
    }

    updateTextFieldValue(textFieldValue)
}
